#pragma once
#include<iostream>
#include<functional>
#include<string>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<unistd.h>
#include<signal.h>
#include<unordered_map>
#include"Protocol.hpp"  

namespace server
{
    enum
    {
        USAGE_ERR = 1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR,
        ACCEPT_ERR
    };

    // req是输入型参数，resp是输出型参数！

    //保证解耦
  

    const static int gbacklog = 5;
    const static uint16_t gport = 8080;
    using func_t = std::function<void(const HttpRequest &, HttpResponse &)>;

    class httpServer
    {
    public:
        httpServer(func_t func,const uint16_t &port = gport)
            : port_(port), listensock_(-1),func_(func)
        {
        }

        void initServer()
        {
            //1.首先就是要创建套接字
            //1.1创建一个套接字！
            listensock_ = socket(AF_INET,SOCK_STREAM,0);
            if(listensock_ == -1)
            {
                exit(SOCKET_ERR);
            }

            //1.2进行绑定！
            struct sockaddr_in peer;
            bzero(&peer,sizeof(peer));
            peer.sin_family = AF_INET;
            peer.sin_addr.s_addr = INADDR_ANY;
            peer.sin_port = htons(port_);
            int n = bind(listensock_,(struct sockaddr*)&peer,sizeof(peer));

            if(n == -1)
            {
                exit(BIND_ERR);
            }

            //3.设置socket 为监听状态！
           if (listen(listensock_, gbacklog) <  0)
           {
               exit(LISTEN_ERR);
           }
        
        }

        void start()
        {

            for (;;)
            {
                signal(SIGCHLD, SIG_IGN); // 直接忽略子进程信号,那么操作系统就会自动回收

                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                int sock = accept(listensock_, (struct sockaddr *)&peer, &len);

                std::cout << sock << std::endl;
                if (sock == -1)
                {
                    continue; 
                }

                pid_t id = fork();
                if (id == 0)
                {
                    close(listensock_);

                    HandlerHttp(sock);


                    close(sock);
                    exit(0);
                }
                close(sock);

            }
        }
        // void RegisterCb(std::string servicename, func_t cb)
        // {
        //     //这是我们自己提供的一个注册方法
        //     funcs.insert({servicename,cb});
        // }
        ~httpServer()
        {
        }

    private:

        void HandlerHttp(int sock)
        {
            //1.获取完整的http请求
            //2.对请求进行反序列化获得结构化数据！
            // HttpRequest req;
            //3.对请求进行处理！
            // HttpResponse resp;
            // func_(req,resp);
            //4.对响应进行序列化！
            //send发送请求！
            char buffer[1024];
            ssize_t n = recv(sock,buffer,sizeof(buffer)-1,0);//我们假设大概率直接就能读取到完整的http请求
            HttpRequest req;
            HttpResponse resp;
            if(n>0)
            {
                buffer[n] = 0;
                req.inbuffer = buffer;
                req.parse();
                func_(req,resp);
                //这个其实要加上前面加上判断判断在不在func里面！但是这里先不进行
                // funcs[req.path](req,resp);//这相当于可以根据未来的路径来进行绑定服务的！

                send(sock,resp.outbuffer.c_str(),resp.outbuffer.size(),0);
            }
        }

    private:
        int listensock_; // tcp服务端也是要有自己的socket的！这个套接字的作用不是用于通信的！而是用于监听连接的！
        uint16_t port_;//tcp服务器的端口
        func_t func_;
        // std::unordered_map<std::string,func_t> funcs;

    };


}